package com.cskaoyan.javase.oop3._1interface._0introduction;

import javafx.animation.Animation;

/**
 * 在猫狗案例的基础上,
 * 现在我们有了新需求：
 * 一部分猫和狗，经过了特殊训练，能够直立行走了。那么这群特殊的猫和狗，怎么描述它们呢？
 *
 * 分析：
 *
 * 部分猫和狗经过特殊训练，才能够直立行走。
 * 所以不可能直接加个方法到Cat类和Dog类中，不是所有猫狗都有这个行为。
 * 而特殊的猫狗仍然是猫和狗，所以它们肯定还要继承猫和狗这两个类。可能很多同学，这时候想到的就是：
 * 重新定义两个新的猫狗类（比如超级狗和猫）继承猫狗，然后给出直立行走的方法就算完事了。
 * 这样做不是不行，需求是实现了，但还有一些小问题：
 *      1.一方面没有体现代码复用。
 *      2.更重要的是，没有体现出特殊训练的过程。
 *      假如还有一些动物也要直立行走，增加这个行为，如何体现出规范性、标准性呢？体现出它们是特殊的经过训练的动物呢？
 *
 * 这里我们想到了抽象类，因为抽象类中抽象方法，可以强制约束子类实现它，这样就是一种标准和规范，体现了它经过了特殊训练，和之前不同了。
 *
 * 于是我们定义抽象类，给出抽象方法，让超级猫狗类去继承这个抽象类，可行吗？
 *
 * 理想很美好，现实很骨感。显然做不到，因为Java不支持多继承。
 * 除开这点这么做也不是完美的，问题是：
 *      1.这个抽象类里面是对功能和行为的抽象，缺少属性（单独一个直立行走的行为是一个什么对象？）所以单独的行为不应该被抽象为类，不符合类的定义。
 *
 *      2.继承这个抽象类也不符合继承的"is-a"关系，这里不适用继承（还是上面那句话，行为根本不是个体）
 *
 *      3.抽象类适用于继承层次中的祖先类,这里也不是祖先类
 *
 * 于是，我们就迫切需要一种全新的数据类型，这种全新的数据类型：
 *      1.不同于类,也不是类,不强调属性，只强调行为的抽象，"继承"它表示功能的扩展。
 *      2.在一个类继承某个类后，还能继续"继承"，不受Java单继承限制。
 *      3.没有"is-a"这种继承关系的限制。
 *      4.不是继承层次中的祖先类(当然它本身就不是类)
 *      5.最好还有抽象方法。（因为它能表示规范和标准）
 * 这种全新的数据类型，就是接口（interface）。
 *
 * 接口的语法:
 * [访问权限修饰符] interface 接口名{
 *     // 接口体
 * }
 * 关于接口定义的说明:
 *      1.接口声明,将声明类时的class关键字变成了关键字"interface"
 *      2.接口是一种完全平行于类的数据类型,它同样是引用数据类型
 *      3.接口名的命名和类名遵循一样的规则,大驼峰,合法单词,见名知意.
 *      特殊的,接口的命名为了更好的显示它是一个接口
 *      有些程序员喜欢用"I"作为接口名的开头(这不是必须的)
 *      4.接口的访问权限修饰符和定义类时完全一样
 *      5.接口中允许定义抽象方法
 *
 *
 * 接口的"继承"(实现):
 *      1.接口定义完后,可以让类去"继承"它
 *      在Java中,这种继承关系,更准确的称呼是"实现"
 *      它不使用关键字"extends",而是使用"implements"
 *
 *      2.如果一个类有继承有实现,应该先继承再实现,顺序不能反.
 *
 *      3.接口的实现和类的继承没有本质上的区别,一个普通类实现接口,会得到接口中的成员,如果接口中存在抽象方法,普通实现类也一样需要实现抽象方法.
 *
 *      4.在接口的实现中,称呼接口是"父接口"(基本等同于父类),实现接口的称之为"实现类"(基本等同于子类)
 *
 *
 * 接口的使用:
 *      从代码上来看,基本上接口的实现类和接口之间的使用,就是"父子类关系"
 *      多态现象,仍然能够发生
 *
 * 注意事项/细节:
 *      1.多类出现继承,实现时,不同引用指向子类对象访问范围不同.
 *      2.接口的实现是多实现的,一个类可以实现很多个接口
 *      3.接口和它的实现类之间不再是"is-a"的继承关系
 *      而是一种"like-a"的关系
 *      总之,这种关系,表现为实现接口,即扩展接口的功能
 *      所以接口的实现表示功能的扩展
 *
 *      4.接口能不能被创建对象?
 *
 *
 * @since 15:41
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        /*IWalkUprightSkill is;
        is = new SuperCat();
        is.walkUpright();
        is = new SuperDog();
        is.walkUpright();*/

        /*
            在本案例中的类中,创建SuperCat的对象,有几种方式?
            它们的区别是什么?
            引用的类型的不一样
            导致引用所能访问的范围是有区别的
          */
        Animal a = new SuperCat();
        a.shout();
        Cat c = new SuperCat();
        c.shout();
        SuperCat sc = new SuperCat();
        sc.shout();
        sc.walkUpright();
        IWalkUprightSkill is = new SuperCat();
        is.walkUpright();

        // 'IA' is abstract; cannot be instantiated
        // new IA();
    }
}

abstract class Animal {
    public abstract void shout();
}

class Cat extends Animal {
    @Override
    public void shout() {
        System.out.println("猫叫");
    }
}

class Dog extends Animal {
    @Override
    public void shout() {
        System.out.println("狗叫");
    }
}

class SuperCat extends Cat implements IWalkUprightSkill, IA, IB, IC {
    @Override
    public void walkUpright() {
        System.out.println("我是超威蓝猫,我两条腿走路~");
    }
}

class SuperDog extends Dog implements IWalkUprightSkill {
    @Override
    public void walkUpright() {
        System.out.println("我是哮天犬,我两条腿走路~");
    }
}

interface IWalkUprightSkill {
    public abstract void walkUpright();
}

interface IA {
}

interface IB {
}

interface IC {
}

// 抽象类仍然是一个类,仍然受Java单继承的限制
abstract class WalkUprightSkill {
    public abstract void walkUpright();
}